AWS Config 設定レコーダーと配信チャネル をCloudFormation で削除する
既存のアカウントをAWS Control Tower に登録する場合、事前にいくつかの作業が必要になります。
その中で、AWS Config 設定レコーダーまたは配信チャネルを削除する事が推奨されています。
登録する既存のアカウントにログイン可能な場合は該当のアカウントのCloudShellなどから CLIで削除する方法などもあり実施等が本ブログでも紹介されています。
コンソールから消せないConfigを全リージョンCLIから無効化する
今回、手動の処理を挟まずAWS Config 設定レコーダーと配信チャネルを削除する必要があったため CloudFormationで実施できるようにCloudFromationのカスタムリソースで作成いたしましたので共有します。
また、既存のアカウントで、AWS Configを止める事ができず、移行する必要がある場合は、サポートケースを起票する等の作業が必要となります。詳細は公式のブログでご紹介されておりますのでConfigを移行する必要がある際は、こちらをご参考ください。
https://aws.amazon.com/jp/blogs/mt/automate-enrollment-of-accounts-with-existing-aws-config-resources-into-aws-control-tower/
AWS Control Tower 登録の前提条件
https://docs.aws.amazon.com/ja_jp/controltower/latest/userguide/enrollment-prerequisites.html
1.アカウントが AWS Config 設定レコーダーまたは配信チャネルを持たないようにすることをお勧めします。
2.登録するアカウントは、AWS Control Tower 管理アカウントと同じ AWS Organizations 組織に存在する必要があります。
3.既存のアカウントを AWS Control Tower に登録する前にAWSControlTowerExecution のRoleが必要です。
となります。削除以外にも実際に登録する場合は事前に、AWSControlTowerExecution Roleの作成や、SCPでの違反がないかなど、の確認が必要となりますので、下記エントリーをご参考にしてください。
CloudFromationのカスタムリソースについて
CloudFormationで作成できない外部リソースやCloudFromationでサポートされていないリソースを作成する際に使用する独自実装処理となりますので、本エントリーで共有している処理をご使用される場合は、検証環境等でご検証のうえ、ご使用ください。
参考
CloudFormation テンプレート説明
テンプレート全体は本ブログの最後に記載します。
Config削除Lambda用のロール
- リージョン一覧取得
- Config の操作の全権限
を定義しています。
DeleteConfigFuncRole: 省略 Policies: - PolicyName: ConfigPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: 'config:*' Resource: '*' - Effect: Allow Action: 'ec2:DescribeRegions' Resource: '*'
Config削除処理を行うLamba関数
- 対象となるリージョン一覧情報の取得
ec2 = boto3.client('ec2') regions = list(map(lambda x: x['RegionName'], ec2.describe_regions()['Regions']))
- 指定されたリージョンのConfig 設定レコーダーまたは配信チャネルの削除を実施
def delete_configuration_recorder(region): config = boto3.client('config', region_name=region) recorders = config.describe_configuration_recorders() for recorder in recorders["ConfigurationRecorders"]: # print (recorder) response = config.delete_configuration_recorder(ConfigurationRecorderName=recorder["name"]) print('%s delete_configuration_recorder ' % region) channels = config.describe_delivery_channels() for channel in channels["DeliveryChannels"]: # print (channel) response = config.delete_delivery_channel(DeliveryChannelName=channel["name"]) print('%s delete_delivery_channel' % region)
を行っています。特に難しい処理は実施していませんが、問答無用で消してますのでご注意ください
やってみる
Config が有効なアカウントにログインを実施します。
※Configが消えても問題のない、検証用のアカウントでご実施ください
CloudShell で現在の状況を確認します。
aws ec2 describe-regions --region ap-northeast-1 --query "Regions[].[RegionName]" --output text \ | while read r; do recorder=$(aws configservice describe-configuration-recorders --region $r \ --query "ConfigurationRecorders[].name" --output text) echo "${r} ${recorder}" done
各リージョンで有効場合、下記のような表示となります
eu-north-1 default ap-south-1 default eu-west-3 default eu-west-2 default eu-west-1 default ap-northeast-3 default ap-northeast-2 default ap-northeast-1 default sa-east-1 default ca-central-1 default ap-east-1 default ap-southeast-1 default ap-southeast-2 default eu-central-1 default us-east-1 default us-east-2 default us-west-1 default us-west-2 default
S3上にテンプレートを共有しておりますので、下記URLをクリックしてスタックを作成ください。
AWS CloudFormation によって IAM リソースが作成される場合があることを承認します。
にチェックを行いスタックを作成します。
- Roleの作成
- 関数の作成
- カスタムリソースの作成
- 実際にはこのタイミングでConfigの削除が行われます。
とすすみ、スタックが正常に作成されるとConfigの削除が実施されます。
削除状況確認
先ほどと同様のコマンドを実施してみます。一覧表示されるのみでレコード(default)がないことが確認できたかと思います。
$ aws ec2 describe-regions --region ap-northeast-1 --query "Regions[].[RegionName]" --output text | while read r; do recorder=$(aws configservice describe-configuration-recorders --region $r \ --query "ConfigurationRecorders[].name" --output text); echo "${r} ${recorder}"; done eu-north-1 ap-south-1 eu-west-3 eu-west-2 eu-west-1 ap-northeast-3 ap-northeast-2 ap-northeast-1 sa-east-1 ca-central-1 ap-east-1 ap-southeast-1 ap-southeast-2 eu-central-1 us-east-1 us-east-2 us-west-1 us-west-2
スタックの削除
カスタムリソース自体ではConfigの復活等の処理は実装していませんので、削除する際はConfigには影響はありません。
Configの削除を行うために作成したRole、Lamba関数が削除されます。
まとめ
多くのアカウントを移行する際など、個別のアカウントに入りConfigを無効化する作業の自動化を行うためにカスタムリソース処理を用いました。
若干、リソースの削除を行うのに、スタックを作成するとはいかに?という気もしなくもないですが、
Oraganizations また、StackSetsと組み合わせて、自動でContorol Tower への移行前に各アカウントで事前の処理を行う際などに有用かと思います。
参考情報
https://dev.classmethod.jp/articles/disable-config-all-region-cli/
CloudFormation テンプレート
AWSTemplateFormatVersion: 2010-09-09 Description: Delete Configuration recorder and Delivery channel Resources: DeleteConfigFuncRole: Type: "AWS::IAM::Role" Properties: Path: "/lambda/servicerole/" ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Principal: Service: [lambda.amazonaws.com] Action: - sts:AssumeRole Policies: - PolicyName: ConfigPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: 'config:*' Resource: '*' - Effect: Allow Action: 'ec2:DescribeRegions' Resource: '*' DeleteConfigFunc: Type: 'AWS::Lambda::Function' Properties: Handler: index.lambda_handler Role: !GetAtt DeleteConfigFuncRole.Arn Code: ZipFile: | import json import boto3 import cfnresponse SUCCESS = "SUCCESS" FAILED = "FAILED" print('Loading function') ec2 = boto3.client('ec2') regions = list(map(lambda x: x['RegionName'], ec2.describe_regions()['Regions'])) def lambda_handler(event, context): # print("Received event: " + json.dumps(event, indent=2)) responseData={} try: if event['RequestType'] == 'Delete': # print("Request Type:", event['RequestType']) print("Sending response to custom resource after Delete") elif event['RequestType'] == 'Create' or event['RequestType'] == 'Update': # print("Request Type:", event['RequestType']) for region in regions: delete_configuration_recorder(region) print("Sending response to custom resource") responseStatus = 'SUCCESS' except Exception as e: print('Failed to process:', e) responseStatus = 'FAILED' responseData = {'Failure': 'Something bad happened.'} cfnresponse.send(event, context, responseStatus, responseData) def delete_configuration_recorder(region): config = boto3.client('config', region_name=region) recorders = config.describe_configuration_recorders() for recorder in recorders["ConfigurationRecorders"]: # print (recorder) response = config.delete_configuration_recorder(ConfigurationRecorderName=recorder["name"]) print('%s delete_configuration_recorder ' % region) channels = config.describe_delivery_channels() for channel in channels["DeliveryChannels"]: # print (channel) response = config.delete_delivery_channel(DeliveryChannelName=channel["name"]) print('%s delete_delivery_channel' % region) Runtime: python3.9 Timeout: 60 MyCustomResource: Type: AWS::CloudFormation::CustomResource Properties: ServiceToken: !GetAtt DeleteConfigFunc.Arn